package edu.msg.jthr.backend.repository.bean;

import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.PersistenceException;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Root;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import edu.msg.jthr.backend.model.AbstractModel;
import edu.msg.jthr.backend.repository.exception.RepositoryException;
import edu.msg.jthr.backend.repository.service.RepositoryInterface;

public class BaseRepoBean<T extends AbstractModel, I> implements
		RepositoryInterface<T, I> {

	@PersistenceContext(unitName = "titan")
	private EntityManager entityManager;
	public Class<T> clazz;
	private static final Logger LOG = LoggerFactory.getLogger(BaseRepoBean.class);

	public BaseRepoBean(Class<T> clazz) {
		this.clazz = clazz;
	}

	@Override
	public List<T> getAll() throws RepositoryException {

		try {
			final CriteriaBuilder cb = entityManager.getCriteriaBuilder();
			final CriteriaQuery<T> criteriaQuery = cb.createQuery(clazz);
			final Root<T> rootEntry = criteriaQuery.from(clazz);
			final CriteriaQuery<T> allQuery = criteriaQuery.select(rootEntry);
			TypedQuery<T> query = entityManager.createQuery(allQuery);
			LOG.info("Get object list successfully!");
			return query.getResultList();
		} catch (IllegalArgumentException | PersistenceException e) {
			LOG.error("Base repo service error: " + e.getMessage(), e);
			throw new RepositoryException("Base repo service error: "
					+ e.getMessage(), e);
		}
	}

	@Override
	public void create(T obj) throws RepositoryException {
		try {
			entityManager.persist(obj);
			entityManager.flush();
			LOG.info("Create object successful!");
		} catch (IllegalArgumentException | PersistenceException e) {
			LOG.error("Base repo service error: " + e.getMessage(), e);
			throw new RepositoryException("Base repo service error: ", e);
		}

	}

	@Override
	public void delete(T obj) throws RepositoryException {
		try {
			T rObj = entityManager.merge(obj);
			entityManager.remove(rObj);
			entityManager.flush();
			LOG.info("Delete object successful!");
		} catch (IllegalArgumentException | PersistenceException e) {
			LOG.error("Base repo service error: " + e.getMessage(), e);
			throw new RepositoryException("Base repo service error: "
					+ e.getMessage(), e);
		}
	}

	@Override
	public T update(T obj) throws RepositoryException {
		try {
			T retObj = entityManager.merge(obj);
			entityManager.flush();
			LOG.info("Update object successful!");
			return retObj;
		} catch (IllegalArgumentException | PersistenceException e) {
			LOG.error("Base repo service error: " + e.getMessage(), e);
			throw new RepositoryException("Base repo service error: "
					+ e.getMessage(), e);
		}
	}

	@Override
	public T getById(I id) throws RepositoryException {
		try {
			T retObj = entityManager.find(clazz, id);
			entityManager.flush();
			LOG.info("Get object by id successful!");
			return retObj;
		} catch (IllegalArgumentException | PersistenceException e) {
			LOG.error("Base repo service error: " + e.getMessage(), e);
			throw new RepositoryException("Base repo service error: "
					+ e.getMessage(), e);
		}
	}

	public EntityManager getEntityManager() {
		return entityManager;
	}

	public void setEntityManager(EntityManager entityManager) {
		this.entityManager = entityManager;
	}

}
